/*
 * Copyright (C) 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.www.coroutinefinshdemo.main

import androidx.lifecycle.LiveData
import androidx.lifecycle.map
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout

/**
 *
 * TitleRepository提供了一个获取标题或请求生成新标题的接口。存储库模块处理数据操作。
 * 它们提供了一个干净的API，以便应用程序的其余部分可以轻松地检索这些数据。
 * 他们知道从哪里获取数据，以及在数据更新时调用什么API。
 * 您可以将存储库视为不同数据源之间的中介，在我们的例子中，它是网络API和离线数据库缓存之间的中介。
 */
class TitleRepository(val network: MainNetwork, val titleDao: TitleDao) {

    /**
     * [LiveData] to load title.
     * LiveData加载标题。
     * 这是加载标题的主界面。标题将从脱机缓存加载。
     * 注意这一点不会导致标题刷新，请使用TitleRepository。refreshTitleWithCallbacks刷新标题。
     */
    val title: LiveData<String?> = titleDao.titleLiveData.map { it?.title }

    /**
     * 刷新当前标题并将结果保存到脱机缓存中。
     * 此方法不返回新标题。使用TitleRepository。标题来观察当前的贴图。
     */
    suspend fun refreshTitle() {
        try {
            val result = withTimeout(5_000) {
                network.fetchNextTitle()
            }
            titleDao.insertTitle(Title(result))
        } catch (error: Throwable) {
            throw TitleRefreshError("Unable to refresh title", error)
        }
    }

    /**
     * 此API公开给Java编程语言的调用者。
     * 请求将以非结构化方式运行，这意味着它不能被取消。
     * Params: titlerfreshcallback—一个回调函数
     */
    fun refreshTitleInterop(titleRefreshCallback: TitleRefreshCallback) {
        val scope = CoroutineScope(Dispatchers.Default)
        scope.launch {
            try {
                refreshTitle()
                titleRefreshCallback.onCompleted()
            } catch (throwable: Throwable) {
                titleRefreshCallback.onError(throwable)
            }
        }
    }
}

/**
 * 当获取新标题时发生错误时抛出
 *
 * @property message user ready error message
 * @property cause the original cause of this exception
 */
class TitleRefreshError(message: String, cause: Throwable?) : Throwable(message, cause)

interface TitleRefreshCallback {
    fun onCompleted()
    fun onError(cause: Throwable)
}
